<?php
/**
 * Created by PhpStorm.
 * Script Name: Onmessage.php
 * Create: 12/25/21 9:43 PM
 * Description:
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace plugin\wechat\app\bot\handler;

use app\common\service\Tenant as TenantService;
use plugin\wechat\app\bot\handler\my\EventFriendVerify;
use plugin\wechat\app\bot\handler\my\EventLogin;
use plugin\wechat\app\bot\handler\my\EventPrivateChat;
use plugin\wechat\app\model\Bot;
use plugin\wechat\app\model\BotGroupmember;
use plugin\wechat\app\model\BotMember;
use app\PluginController;
use plugin\wechat\app\bot\handler\cat\EventGroupMemberAdd;
use plugin\wechat\app\service\Bot as BotService;
use plugin\wechat\extend\WxBot\Driver\Cat;
use plugin\wechat\extend\WxBot\Driver\Qianxun;
use plugin\wechat\extend\WxBot\Driver\Vlw;
use plugin\wechat\extend\WxBot\Driver\Xbot;

class Handler extends PluginController
{
    public function __construct()
    {
        parent::__construct();
        $this->botM = new Bot();
        $this->memberM = new BotMember();
        $this->groupMemberM = new BotGroupmember();
    }

    /**
     * @var Bot
     */
    protected $botM;
    /**
     * @var BotMember
     */
    protected $memberM;
    /**
     * @var BotGroupmember
     */
    protected $groupMemberM;

    /**
     * 兼容fpm框架
     * @param $name
     * @return mixed|null
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function __get($name)
    {
        $request = \request();
        return $request->$name;
    }

    /**
     * 兼容fpm框架
     * @param $property
     * @param $value
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    function __set($property, $value ){
        $request = \request();
        return $request->$property = $value;
    }

    /**
     * 入口
     * tip:
     * 1.机器人对某个好友的私聊不会有回调
     * 2.机器人在群里发的情况下，from_wxid和from_group 都为空
     * @param array $options
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function serve($options = []){
        $request = \request();
        $request->addonOptions = $options;
        $this->checkEvent();

        $class = "\\plugin\\wechat\\app\\bot\\handler\\{$request->driver}\\" . ucfirst($request->event);
        if(! class_exists($class)){
            halt("class: " . $class . " not exists!");
        }

        /**
         * @var $handler EventLogin|EventFriendVerify|EventPrivateChat|EventGroupMemberAdd
         */
        $handler = new $class();
        $handler->initData($options);
        $handler->handle();

        //response
        $this->response();
    }

    /**
     * 全局参数
     * @param array $options
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function initData($options = []){
        $request = \request();

        switch ($request->driver){
            case BotService::PROTOCOL_XBOT:
                $request->botWxid = empty($request->ajaxData['wxid']) ? (empty($request->content['wxid'])?'':$request->content['wxid']) : $request->ajaxData['wxid'];
                $request->fromWxid = empty($request->content['from_wxid']) ? '' : $request->content['from_wxid'];
                !empty($request->content['wx_type']) && $request->content['type'] = $request->content['wx_type'];
                !empty($request->content['msgid']) && $request->content['msg_id'] = $request->content['msgid'];
                break;
            case BotService::PROTOCOL_QXUN:
                $request->botWxid = $request->ajaxData['wxid'];
                $request->fromWxid = empty($request->content['finalFromWxid']) ? (
                empty($request->content['fromWxid']) ? $request->botWxid : $request->content['fromWxid']
                ) : $request->content['finalFromWxid'];
                break;
            case BotService::PROTOCOL_WEB:
                $request->botWxid = $request->content['robot_wxid'];
                $request->fromWxid = empty($request->content['from_wxid']) ? $request->botWxid : $request->content['from_wxid'];
                break;
            case BotService::PROTOCOL_CAT:
                $request->botWxid = $request->content['robot_wxid'];
                $request->fromWxid = empty($request->content['final_from_wxid']) ? $request->botWxid : $request->content['final_from_wxid'];
                break;
            default:
                $request->botWxid = !empty($request->content['robot_wxid']) ? $request->content['robot_wxid'] : $request->content['Wxid'];
                $request->fromWxid = empty($request->content['from_wxid']) ? $request->botWxid : $request->content['from_wxid'];
                $request->fromName = $request->content['from_name'] ?? '';
                break;
        }
        
        if(! in_array($request->event, [BotService::EVENT_LOGIN_CODE, BotService::EVENT_CONNECTED])){
            $this->getBot($request->botWxid);
            $request->botClient = BotService::getRobotClient($request->bot);
        }
        $request->beAtStr = [
            '[at='.$this->botWxid.']',
            "@{$this->bot['nickname']}"
        ];
    }

    public function checkEvent(){
        $request = \request();
        switch ($request->driver){
            case BotService::PROTOCOL_XBOT:
                $request->content = $request->ajaxData['data'] ?? [];
                $map = [
                    Xbot::EVENT_LOGIN_CODE => BotService::EVENT_LOGIN_CODE,
                    Xbot::EVENT_CONNECTED => BotService::EVENT_CONNECTED,
                    Xbot::EVENT_LOGIN => BotService::EVENT_LOGIN,
                    Xbot::EVENT_LOGOUT => BotService::EVENT_LOGOUT,
                    Xbot::EVENT_GROUP_MEMBER_ADD => BotService::EVENT_GROUP_MEMBER_ADD,
                    Xbot::EVENT_GROUP_MEMBER_DEC => BotService::EVENT_GROUP_MEMBER_DEC
                ];
                $request->event = isset($map[$request->ajaxData['type']]) ? $map[$request->ajaxData['type']] : $request->ajaxData['type'];
                if(!empty($request->content['from_wxid'])){
                    $request->event = BotService::EVENT_PRIVATE_CHAT;
                    if(!empty($request->content['room_wxid'])){
                        $request->event = BotService::EVENT_GROUP_CHAT;
                    }
                }
                if($this->isGroupEvent()){
                    $request->groupWxid = $request->content['room_wxid'];
                }
                break;
            case BotService::PROTOCOL_QXUN:
                $request->content = empty($request->ajaxData['data']['data']) ? $request->ajaxData['data'] : $request->ajaxData['data']['data'];
                !empty($request->content['msgType']) && $request->content['type'] = $request->content['msgType'];
                $map = [
                    Qianxun::EVENT_LOGIN => BotService::EVENT_LOGIN,
                    Qianxun::EVENT_PRIVATE_CHAT => BotService::EVENT_PRIVATE_CHAT,
                    Qianxun::EVENT_GROUP_CHAT => BotService::EVENT_GROUP_CHAT,
                ];
                $request->event = isset($map[$request->ajaxData['event']]) ? $map[$request->ajaxData['event']] : $request->ajaxData['event'];
                if($this->isGroupEvent()){
                    $request->groupWxid = $request->content['fromWxid'];
                }
                break;
            case BotService::PROTOCOL_WEB:
                $request->content = $request->ajaxData;
                $request->event = $request->ajaxData['event'];
                if($this->isGroupEvent()){
                    $request->groupWxid = $request->content['from_group'];
                    $request->groupName = $request->content['from_group_name'];
                }
                break;
            case BotService::PROTOCOL_CAT:
                $request->content = $request->ajaxData;
                $map = [
                    Cat::EVENT_FRIEND_MSG => BotService::EVENT_PRIVATE_CHAT,
                    Cat::EVENT_GROUP_MSG => BotService::EVENT_GROUP_CHAT,
                    Cat::EVENT_LOGIN => BotService::EVENT_LOGIN,
                    Cat::EVENT_GROUP_MEMBER_ADD => BotService::EVENT_GROUP_MEMBER_ADD,
                    Cat::EVENT_GROUP_MEMBER_DEC => BotService::EVENT_GROUP_MEMBER_DEC
                ];
                $request->event = isset($map[$request->ajaxData['event']]) ? $map[$request->ajaxData['event']] : $request->ajaxData['event'];
                if($this->isGroupEvent()){
                    $request->groupWxid = $request->content['from_wxid'];
                    $request->groupName = $request->content['from_name'];
                }
                break;
            default:
                $request->content = $request->ajaxData['content'];
                $map = [
                    Vlw::EVENT_FRIEND_VERIFY => BotService::EVENT_FRIEND_VERIFY,
                    Vlw::EVENT_LOGIN => BotService::EVENT_LOGIN,
                ];
                $request->event = isset($map[$request->ajaxData['Event']]) ? $map[$request->ajaxData['Event']] : $request->ajaxData['Event'];

                if($this->isGroupEvent()){
                    $request->groupWxid = $request->content['from_group'];
                    $request->groupName = $request->content['from_group_name'];
                }
                break;
        }
    }

    public function isGroupEvent(){
        $request = \request();
        return in_array($request->event, [
            BotService::EVENT_GROUP_CHAT,
            BotService::EVENT_GROUP_MEMBER_ADD,
            BotService::EVENT_GROUP_MEMBER_DEC
        ]);
    }

    /**
     * @param string $nickname
     * @return array|false|\PDOStatement|string|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function getGroupMemberByNickname($nickname=''){
        $request = \request();
        $group = $this->memberM->where([
                ['uin' ,'=', $request->bot['uin']],
                ['wxid' ,'=', $request->groupWxid]
            ])->field(['id'])
            ->find();
        return $this->groupMemberM->where([
            ['nickname' ,'=', $nickname],
            ['group_id' ,'=', $group['id']]
        ])->find();
    }

    /**
     * 获取机器人信息
     * @param string $uin
     * @return mixed
     * @throws \Exception
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function getBot($uin = ''){
        $request = \request();
        $map = [
            ['uin','=', $uin]
        ];
        if($request->event !== BotService::EVENT_LOGIN){
            $map[] = ['alive', '=', 1];
        }
        if(! $request->bot = $this->botM->where($map)->find()) {
            halt('Bot not exists or not logged in: ' . $uin);
        }
        return $request->bot;
    }

    protected function getAddonOptions(){
        $request = \request();
        $request->addonOptions['driver'] = $request->driver;
        $request->addonOptions['ajax_data'] = $request->ajaxData;
        $request->addonOptions['bot'] = $request->bot;
        $request->addonOptions['bot_client'] = $request->botClient;
        $request->addonOptions['bot_wxid'] = $request->botWxid;
        $request->addonOptions['from_wxid'] = $request->fromWxid;
        $request->addonOptions['group_wxid'] = $request->groupWxid;
        $request->addonOptions['event'] = $request->event;
        $request->addonOptions['group'] = $request->group;
        $request->addonOptions['content'] = $request->content;
        $request->addonOptions['is_new_friend'] = $request->isNewFriend;
        return $request->addonOptions;
    }

    private function response()
    {
        $request = \request();
        switch ($request->driver){
            case BotService::PROTOCOL_QXUN:
                return Qianxun::response();
        }
    }
}